<?php

class getDataXmeterTask extends baseWemTask
{
    
    private $localDir;
    private $localTmpDir;
    private $url;
    private $remoteDir;
    private $ftpUser;
    private $ftpPass;
    private $urlComp;
    private $objReader;
    private $filename;

    
    //each key must be unique
    static public $EtXmeter_Var = array(
        "sampleTime"=>"tstamp",
        "ActExpEn.Exchange"=>"ExpEnA",
        "ActImpEn"=>"ImpEnA",
        "ActExpEn.GSE"=>"Prod",
        "Irr"=>"Irrag",
        "Tmod"=>"TMod",
        "Tenv"=>"TAmb",);
    
    
    public function configure()
    {
        parent::configure();
        
        $this->name      = 'getData-Xmeter';
        $this->briefDescription = 'Get Data from Energy Team Xmeter';
        $this->sourceName = 'EtXmeter';
        
        $this->localDir="//192.168.0.37/om/NUOVO SERVER O&M/6_MONITORAGGIO/1_DATA/";
        $this->localTmpDir="C:/wamp/www/seth/data/tmp/";
        $this->url="ftp://ftp.enerqos.com:21";
        $this->remoteDir="";
        $this->ftpUser="testfulvio";
        $this->ftpPass="eqmonitoring";
        
        //ARGUMENTS
        $this->addArgument('plant',  sfCommandArgument::REQUIRED,'Plant to check');
        $this->addArgument('start',  sfCommandArgument::OPTIONAL,'The starting day [Format: Y-m-d]',0);
        $this->addArgument('days',  sfCommandArgument::OPTIONAL,'Number of days to check [the greater the range the longer the script..] ',5);
    }
    public function execute($arguments = array(), $options = array())
    {   
        //Get DB Connection
        $this->ConnectDB();
        
        //register task execution
        $tasklog=seth::regTaskStart($this->name, $arguments, $options );

        
        //get the requested plant
        $plant=new Plant();
        $plant=Doctrine_Core::getTable('plant')->find($arguments['plant']);
        if (!is_object($plant)){
            $this->logBlock("The provided plant does not exist", "ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        
        //check the compatibility between this task and plant devices sources
        $sources=$plant->getPowerdevSources();
        if (array_search($this->sourceName, $sources)===FALSE){
                //no sources for this task type
            $this->logBlock("No device in ".$plant->getName()." monitored by ".$this->sourceName, "ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        //register log file
        $this->addFileLogger($plant->getName());
            
        if(filter_var($this->url, FILTER_VALIDATE_URL) === FALSE)
        { 
            $this->logBlock("The provided URL is not valid", "ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        
        $this->urlComp=parse_url($this->url);
        if (!(isset($this->urlComp['scheme']) and isset($this->urlComp['host']) and isset($this->urlComp['port'])))
        {
            $this->logBlock("The provided URL is not complete. \n You must provide both the SCHEME (Ex. ftp or http) and the HOST (Ex. 192.168.0.1 or www.google.it) and the PORT (Ex 21). \n\n Example: ftp://ftp.power-one.it:21", "ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        } 
            
       /*
        * FTP CONNECTION
        */
        $this->logBlock("Trying to connect to ".$this->url."...","INFO");
        $ftp=new wemFtp();
        
        // OPEN FTP SOCKET
        if ($ftp->open($this->urlComp['host'], $this->urlComp['port']))
         {
            $this->logBlock("Connection to ".$this->url." established.\n Trying to authenticate...","INFO");
         } else {
             $this->logBlock("Connection to ".$this->url." failed. URL is unreachable","ERROR");
             seth::regTaskEnd($tasklog, false);
             die();
        }
        
        //LOGIN
        if ($ftp->login($this->ftpUser, $this->ftpPass)) {
            $this->logBlock("Connected as ".$this->ftpUser."@".$this->url,"INFO");
        } else {
            $this->logBlock("Username or password invalid\n","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        
        // SET PASSIVE MODE
        if ($ftp->setPassv())
            $this->logBlock("Turned in PASSIVE mode.","INFO");
        else
            {
            $this->logBlock("Passive mode Error. Connection aborted. ","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        
        //RETRIEVE FILE LIST
        $files=$ftp->getList($this->remoteDir);
        if (!$files){
            $this->logBlock("Connection to ".$this->url." failed getting files list. URL is unreachable","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }
        

        //SEARCH FOR DATA TO DOWNLOAD
        //For each plant's device it gets from the last updated record in the var"Dev_Type" table:
        //  - Last Sample Time
        //  - Last Source
        //  - Last Soure Id
        // For each plant device type (Meter, Inverter...) collects the previous info in this way:
        //  - Last Sample Time: the lowest sample time of all the device of that type
        //  - Last Source: the source should be the same for each device type
        //  - Last Source Id: the greatest Id for each type
       
        
        /* TIME RANGE DEFINITION */
        if ($arguments["start"]==0)
            $dStart=new DateTime();
        elseif (strtotime($arguments["start"]) == FALSE){
            $this->logBlock("Argument [start] provided is not valid. Must be a number >0","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }else
            $dStart=new DateTime($arguments["start"]);
            
        if (!is_numeric($arguments["days"]) or $arguments["days"]<=0){
            $this->logBlock("Argument [days] provided is not valid. Must be a number >0","ERROR");
            seth::regTaskEnd($tasklog, false);
            die();
        }else
            $days=$arguments["days"];
        
        $rangeLimit=$dStart->sub(new DateInterval("P".$days."D"));
        
        $plantName=str_replace(" ", "_", $plant->getName());
        
        $plantLastUpdate=$plant->getLastUpdate();
        if (!isset($plantLastUpdate)){
            $plantLastUpdate=new DateTime();
            $plantLastUpdate->setTimestamp(0);
        }
        $plantLastUpdate=$plantLastUpdate>=$rangeLimit?$plantLastUpdate:$rangeLimit;
        $today=new DateTime();
        $today->setTime("00","00","00");
        
        //Local Directory definition: it stores the downloaded files from FTP server     
        $this->localDir=$this->localDir.$plant->getName();
        if (!is_dir($this->localDir)){
            if(!isset($fs))
                $fs=new sfFilesystem();
            $fs->mkdirs($this->localDir);
        }
        $this->localDir=$this->localDir."/";
        
        $devs=$plant->getMonitoredPowerDev();
        
        $updateFlag=false;
        foreach ($files as $file){
            
           $this->filename=substr($file,strlen($this->remoteDir));
          
           
           if (strripos($this->filename,$plantName) !== false){
                //$file relativo a $plant

               
                //data e ora dell'ultima modifica al file
                $fileDate=new DateTime();
                $timeStamp=$ftp->getMdTime($file);
                
                if ($timeStamp>0){
                    if ($options['debug']){
                    echo "\n Time Stamp ".date("Y-m-d H:i:s",$timeStamp);
                }
                    $fileDate->setTimestamp ($timeStamp); 
                    if ($fileDate->format("H")<5){
                        $fileDate->modify("- 300 minutes");
                    }
                    
                }
                else{
                     $this->logBlock("Connection to ".$this->url." failed getting last mod time. URL is unreachable","ERROR");
                     seth::regTaskEnd($tasklog, false);
                     die();
                }

                if ($options['debug']){
                    echo "\n".$this->filename." date ".$fileDate->format("Y-m-d H:i:s")." Last Update ".$plantLastUpdate->format("Y-m-d H:i:s");
                    var_dump($fileDate>$plantLastUpdate);
                }
                    
                if ($fileDate>$plantLastUpdate){
                    //$file dev'essere aperto

                    //FILE DOWNLOAD      
                    $path=$this->localTmpDir.$this->filename;
                    if($ftp->getFile($path, $file)){
                        
                        $this->logBlock("\n".$path." succesfully downloaded.","INFO");
                        
                        //load file in a simpleXml object
                        $this->logBlock("Opening ".$path,"INFO");
                        $ts=microtime(true);
                        $xmlObj = simplexml_load_file($path);
                        
                        if ($xmlObj)
                        {
                            $this->logBlock($this->filename." succesfully opened in ".round(microtime(true)-$ts,3)." s","INFO");
                            
                            $attr="day";
                            $day=new DateTime($xmlObj->attributes()->$attr);
                          
                            $i=0;
                            foreach ($xmlObj as $tag=>$val){
                                
                                
                                if ($options['debug'])
                                 echo "\nMem usage is: ",(memory_get_usage()/1024), "KB \n";
                                
                                    if ($tag=="MEAS"){
                                        $addr=$i;

                                        $foundDev=false;
                                        foreach ($devs as $dev){
                                            if (strripos($dev->getAddress(), strval($addr))!== FALSE){
                                                $foundDev=true;
                                                break;
                                            }  
                                        }     

                                        if ($foundDev){

                                            $type=$dev->getType();

                                            if ($this->getDataByElement($val,$dev,$day)){
                                                if (!$updateFlag)
                                                    $updateFlag=true;
                                            }
                                            unset($type);
                                        }else
                                            $this->logBlock(" Device with address ".$addr." not found.","ERROR"); 
                                        unset($dev);
                                        $i++;
                                    }
                            }
                            
                            /* if the file is older than today
                             * move it from tmp dir to local dir and delete from FTP server
                             */
                            if ($fileDate<$today){
                                if(!isset($fs))
                                    $fs=new sfFilesystem();
                                
                                $fs->copy($path, $this->localDir.$this->filename,array("override"=>true));
                                if (is_file($this->localDir.$this->filename)){
                                     $this->logBlock($this->filename." moved to ".$this->localDir,"INFO");
//                                    if($ftp->delFile($file))
//                                        $this->logBlock($this->filename." removed from remote FTP server ".$this->url,"INFO");
//                                    else
//                                        $this->logBlock(" Error removing ".$this->filename." from FTP server. Try manually.","ERROR");
                                }else
                                    $this->logBlock(" Error moving ".$this->filename." to local folder. Still in tmp folder.","ERROR");
                            } 
                            unset($xmlObj);
                            unset($tag);
                            unset($val);
                            gc_collect_cycles();
                        }else
                            $this->logBlock("Error opening ".$this->filename.". Going to next file..","ERROR");
                        
                        //delete from tmp Folder
                        if (!isset($fs))
                            $fs=new sfFilesystem ();
                            $fs->remove($path);
                    }else
                        $this->logBlock(" Error downloading ".$this->filename.". Going to next file..","ERROR");  
                } 

            unset($this->filename);
            unset($fileDate);
          }
        }       
        if (!$updateFlag)
            $this->logBlock("No Updates available for ".$plant,"INFO");
        else{
            $this->logBlock($plant." updated. ","INFO");
        }
        $ftp->close();
        unset($fs);
        unset($ftp);
        seth::regTaskEnd($tasklog, TRUE);        
    }
    
    private function getDataByElement(SimpleXMLElement $meas, Powerdev $dev, DateTime $day){
        
        $ts=microtime(TRUE);
        
        $attr="id";
        $wemVar=array_search($meas->attributes()->$attr, self::$EtXmeter_Var);
        
        $attr="int";
        $sampleLength=$meas->attributes()->$attr;
        //if "." is present, takes only the left part before the "."
        if (strpos($wemVar, ".")){
            $tmp=explode(".", $wemVar);
            $wemVar=$tmp[0];
        }
        
        $insertCount=0;
        if ($wemVar){         
            $day->setTime(0, 0, 0);
            $sampleTime=new DateTime($day->format("Y-m-d H:i:s"));
            
            $samples=explode(";", str_replace("\n", "", $meas));
            foreach ($samples as $key=>$val){    
                if ($val<>"*"){
                    $value=floatval(number_format($val, 2,".",""));
                    
                    if ($dev->getSubtype()=="Exchange")
                        //from Wh->kWh
                        $value=$value/1000;
                    
                    if (strpos($wemVar, "Act")!== FALSE){
                       //X Meter sends the production of the sample. To get the cumulative value it must be added to the previous sample, if it exists
                        $prev=$dev->getVarPrevVal($sampleTime);
                        if ($prev!==FALSE){
                            $method="get".$wemVar;
                            $value=$prev->$method()+$value;
                        }
                    }
                    
                   // echo "\n".$sampleTime->format("Y-m-d H:i:s")." : ".$value;
                    if ($this->tryInsert($sampleTime, $value, $dev, $wemVar)){
                        $insertCount++;
                    }       
                }
                $sampleTime->modify("+".$sampleLength." minutes");
            }
            
            if ($insertCount>0){
                $this->logBlock("\t Inserted ".$insertCount." records for ".$dev.": ".$wemVar.". Process took ".round((microtime(TRUE) - $ts),3)."s ", "INFO");
                return true;
            }else{
                $this->logBlock("\t No record inserted for ".$dev.": ".$wemVar.".", "INFO");
                return false;
            }
            
        }else{
             $this->logBlock(" Variable ".$meas->attributes()->$attr." is not handled by ".$this->name,"ERROR");
             return false;
        }
    }
    
    private function tryInsert($sampleTime, $value, $dev, $wemVar){
      
      $result=false;
      
      $newVar=$dev->getVar(array(
          "sample"=>$sampleTime,
          "source"=>$this->filename
      ));
      
      if ($newVar->count()==0){        
        $class=$dev->getVarTableName();
        $newVar= new $class();
        $newVar->setDev($dev);
        $newVar->setSource($this->filename);
        $newVar->setSampletime($sampleTime->format("Y-m-d H:i:s"));
      }else{
          $newVar=$newVar->getFirst();
          $method="get".$wemVar;
          
          if (!is_null($newVar->$method())){
              return false;
          }      
      }
      
      $method="set".$wemVar;
      $newVar->$method($value);
                                                                                                                                                                        
      try{
        $newVar->save();
        $result=true;
        }catch(Doctrine_Exception $e){}

        $newVar->free(true);
        unset($newVar);
        
        return $result;
    }
}


?>

